home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / ncurses-5.3.lha / ncurses-5.3 / progs / dump_entry.c < prev    next >
C/C++ Source or Header  |  2002-10-24  |  28KB  |  1,089 lines

  1. /****************************************************************************
  2.  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
  3.  *                                                                          *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a  *
  5.  * copy of this software and associated documentation files (the            *
  6.  * "Software"), to deal in the Software without restriction, including      *
  7.  * without limitation the rights to use, copy, modify, merge, publish,      *
  8.  * distribute, distribute with modifications, sublicense, and/or sell       *
  9.  * copies of the Software, and to permit persons to whom the Software is    *
  10.  * furnished to do so, subject to the following conditions:                 *
  11.  *                                                                          *
  12.  * The above copyright notice and this permission notice shall be included  *
  13.  * in all copies or substantial portions of the Software.                   *
  14.  *                                                                          *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  16.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
  18.  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  21.  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  22.  *                                                                          *
  23.  * Except as contained in this notice, the name(s) of the above copyright   *
  24.  * holders shall not be used in advertising or otherwise to promote the     *
  25.  * sale, use or other dealings in this Software without prior written       *
  26.  * authorization.                                                           *
  27.  ****************************************************************************/
  28.  
  29. /****************************************************************************
  30.  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
  31.  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
  32.  *     and: Thomas E. Dickey 1996 on                                        *
  33.  ****************************************************************************/
  34.  
  35. #define __INTERNAL_CAPS_VISIBLE
  36. #include <progs.priv.h>
  37.  
  38. #include "dump_entry.h"
  39. #include "termsort.c"        /* this C file is generated */
  40. #include <parametrized.h>    /* so is this */
  41.  
  42. MODULE_ID("$Id: dump_entry.c,v 1.64 2002/09/01 17:54:43 tom Exp $")
  43.  
  44. #define INDENT            8
  45. #define DISCARD(string) string = ABSENT_STRING
  46. #define PRINTF (void) printf
  47.  
  48. typedef struct {
  49.     char *text;
  50.     size_t used;
  51.     size_t size;
  52. } DYNBUF;
  53.  
  54. static int tversion;        /* terminfo version */
  55. static int outform;        /* output format to use */
  56. static int sortmode;        /* sort mode to use */
  57. static int width = 60;        /* max line width for listings */
  58. static int column;        /* current column, limited by 'width' */
  59. static int oldcol;        /* last value of column before wrap */
  60. static bool pretty;        /* true if we format if-then-else strings */
  61.  
  62. static DYNBUF outbuf;
  63. static DYNBUF tmpbuf;
  64.  
  65. /* indirection pointers for implementing sort and display modes */
  66. static const int *bool_indirect, *num_indirect, *str_indirect;
  67. static NCURSES_CONST char *const *bool_names;
  68. static NCURSES_CONST char *const *num_names;
  69. static NCURSES_CONST char *const *str_names;
  70.  
  71. static const char *separator, *trailer;
  72.  
  73. /* cover various ports and variants of terminfo */
  74. #define V_ALLCAPS    0    /* all capabilities (SVr4, XSI, ncurses) */
  75. #define V_SVR1        1    /* SVR1, Ultrix */
  76. #define V_HPUX        2    /* HP/UX */
  77. #define V_AIX        3    /* AIX */
  78. #define V_BSD        4    /* BSD */
  79.  
  80. #if NCURSES_XNAMES
  81. #define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
  82. #else
  83. #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
  84. #endif
  85.  
  86. #define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
  87.  
  88. #if NCURSES_XNAMES
  89. #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
  90. #define NumIndirect(j)  ((j >= NUMCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
  91. #define StrIndirect(j)  ((j >= STRCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
  92. #else
  93. #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
  94. #define NumIndirect(j)  ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
  95. #define StrIndirect(j)  ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
  96. #endif
  97.  
  98. static void
  99. strncpy_DYN(DYNBUF * dst, const char *src, size_t need)
  100. {
  101.     size_t want = need + dst->used + 1;
  102.     if (want > dst->size) {
  103.     dst->size += (want + 1024);    /* be generous */
  104.     dst->text = typeRealloc(char, dst->size, dst->text);
  105.     }
  106.     (void) strncpy(dst->text + dst->used, src, need);
  107.     dst->used += need;
  108.     dst->text[dst->used] = 0;
  109. }
  110.  
  111. static void
  112. strcpy_DYN(DYNBUF * dst, const char *src)
  113. {
  114.     if (src == 0) {
  115.     dst->used = 0;
  116.     strcpy_DYN(dst, "");
  117.     } else {
  118.     strncpy_DYN(dst, src, strlen(src));
  119.     }
  120. }
  121.  
  122. #if NO_LEAKS
  123. static void
  124. free_DYN(DYNBUF * p)
  125. {
  126.     if (p->text != 0)
  127.     free(p->text);
  128.     p->text = 0;
  129.     p->size = 0;
  130.     p->used = 0;
  131. }
  132.  
  133. void
  134. _nc_leaks_dump_entry(void)
  135. {
  136.     free_DYN(&outbuf);
  137.     free_DYN(&tmpbuf);
  138. }
  139. #endif
  140.  
  141. NCURSES_CONST char *
  142. nametrans(const char *name)
  143. /* translate a capability name from termcap to terminfo */
  144. {
  145.     const struct name_table_entry *np;
  146.  
  147.     if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0)
  148.     switch (np->nte_type) {
  149.     case BOOLEAN:
  150.         if (bool_from_termcap[np->nte_index])
  151.         return (boolcodes[np->nte_index]);
  152.         break;
  153.  
  154.     case NUMBER:
  155.         if (num_from_termcap[np->nte_index])
  156.         return (numcodes[np->nte_index]);
  157.         break;
  158.  
  159.     case STRING:
  160.         if (str_from_termcap[np->nte_index])
  161.         return (strcodes[np->nte_index]);
  162.         break;
  163.     }
  164.  
  165.     return (0);
  166. }
  167.  
  168. void
  169. dump_init(const char *version, int mode, int sort, int twidth, int traceval,
  170.       bool formatted)
  171. /* set up for entry display */
  172. {
  173.     width = twidth;
  174.     pretty = formatted;
  175.  
  176.     /* versions */
  177.     if (version == 0)
  178.     tversion = V_ALLCAPS;
  179.     else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
  180.          || !strcmp(version, "Ultrix"))
  181.     tversion = V_SVR1;
  182.     else if (!strcmp(version, "HP"))
  183.     tversion = V_HPUX;
  184.     else if (!strcmp(version, "AIX"))
  185.     tversion = V_AIX;
  186.     else if (!strcmp(version, "BSD"))
  187.     tversion = V_BSD;
  188.     else
  189.     tversion = V_ALLCAPS;
  190.  
  191.     /* implement display modes */
  192.     switch (outform = mode) {
  193.     case F_LITERAL:
  194.     case F_TERMINFO:
  195.     bool_names = boolnames;
  196.     num_names = numnames;
  197.     str_names = strnames;
  198.     separator = twidth ? ", " : ",";
  199.     trailer = "\n\t";
  200.     break;
  201.  
  202.     case F_VARIABLE:
  203.     bool_names = boolfnames;
  204.     num_names = numfnames;
  205.     str_names = strfnames;
  206.     separator = twidth ? ", " : ",";
  207.     trailer = "\n\t";
  208.     break;
  209.  
  210.     case F_TERMCAP:
  211.     case F_TCONVERR:
  212.     bool_names = boolcodes;
  213.     num_names = numcodes;
  214.     str_names = strcodes;
  215.     separator = ":";
  216.     trailer = "\\\n\t:";
  217.     break;
  218.     }
  219.  
  220.     /* implement sort modes */
  221.     switch (sortmode = sort) {
  222.     case S_NOSORT:
  223.     if (traceval)
  224.         (void) fprintf(stderr,
  225.                "%s: sorting by term structure order\n", _nc_progname);
  226.     break;
  227.  
  228.     case S_TERMINFO:
  229.     if (traceval)
  230.         (void) fprintf(stderr,
  231.                "%s: sorting by terminfo name order\n", _nc_progname);
  232.     bool_indirect = bool_terminfo_sort;
  233.     num_indirect = num_terminfo_sort;
  234.     str_indirect = str_terminfo_sort;
  235.     break;
  236.  
  237.     case S_VARIABLE:
  238.     if (traceval)
  239.         (void) fprintf(stderr,
  240.                "%s: sorting by C variable order\n", _nc_progname);
  241.     bool_indirect = bool_variable_sort;
  242.     num_indirect = num_variable_sort;
  243.     str_indirect = str_variable_sort;
  244.     break;
  245.  
  246.     case S_TERMCAP:
  247.     if (traceval)
  248.         (void) fprintf(stderr,
  249.                "%s: sorting by termcap name order\n", _nc_progname);
  250.     bool_indirect = bool_termcap_sort;
  251.     num_indirect = num_termcap_sort;
  252.     str_indirect = str_termcap_sort;
  253.     break;
  254.     }
  255.  
  256.     if (traceval)
  257.     (void) fprintf(stderr,
  258.                "%s: width = %d, tversion = %d, outform = %d\n",
  259.                _nc_progname, width, tversion, outform);
  260. }
  261.  
  262. static TERMTYPE *cur_type;
  263.  
  264. static int
  265. dump_predicate(int type, int idx)
  266. /* predicate function to use for ordinary decompilation */
  267. {
  268.     switch (type) {
  269.     case BOOLEAN:
  270.     return (cur_type->Booleans[idx] == FALSE)
  271.         ? FAIL : cur_type->Booleans[idx];
  272.  
  273.     case NUMBER:
  274.     return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
  275.         ? FAIL : cur_type->Numbers[idx];
  276.  
  277.     case STRING:
  278.     return (cur_type->Strings[idx] != ABSENT_STRING)
  279.         ? (int) TRUE : FAIL;
  280.     }
  281.  
  282.     return (FALSE);        /* pacify compiler */
  283. }
  284.  
  285. static void set_obsolete_termcaps(TERMTYPE * tp);
  286.  
  287. /* is this the index of a function key string? */
  288. #define FNKEY(i)    (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
  289.  
  290. /*
  291.  * If we configure with a different Caps file, the offsets into the arrays
  292.  * will change.  So we use an address expression.
  293.  */
  294. #define BOOL_IDX(name) (&(name) - &(CUR Booleans[0]))
  295. #define NUM_IDX(name)  (&(name) - &(CUR Numbers[0]))
  296. #define STR_IDX(name)  (&(name) - &(CUR Strings[0]))
  297.  
  298. static bool
  299. version_filter(int type, int idx)
  300. /* filter out capabilities we may want to suppress */
  301. {
  302.     switch (tversion) {
  303.     case V_ALLCAPS:        /* SVr4, XSI Curses */
  304.     return (TRUE);
  305.  
  306.     case V_SVR1:        /* System V Release 1, Ultrix */
  307.     switch (type) {
  308.     case BOOLEAN:
  309.         return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
  310.     case NUMBER:
  311.         return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
  312.     case STRING:
  313.         return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
  314.     }
  315.     break;
  316.  
  317.     case V_HPUX:        /* Hewlett-Packard */
  318.     switch (type) {
  319.     case BOOLEAN:
  320.         return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
  321.     case NUMBER:
  322.         return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
  323.     case STRING:
  324.         if (idx <= STR_IDX(prtr_non))
  325.         return (TRUE);
  326.         else if (FNKEY(idx))    /* function keys */
  327.         return (TRUE);
  328.         else if (idx == STR_IDX(plab_norm)
  329.              || idx == STR_IDX(label_on)
  330.              || idx == STR_IDX(label_off))
  331.         return (TRUE);
  332.         else
  333.         return (FALSE);
  334.     }
  335.     break;
  336.  
  337.     case V_AIX:        /* AIX */
  338.     switch (type) {
  339.     case BOOLEAN:
  340.         return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
  341.     case NUMBER:
  342.         return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
  343.     case STRING:
  344.         if (idx <= STR_IDX(prtr_non))
  345.         return (TRUE);
  346.         else if (FNKEY(idx))    /* function keys */
  347.         return (TRUE);
  348.         else
  349.         return (FALSE);
  350.     }
  351.     break;
  352.  
  353.     case V_BSD:        /* BSD */
  354.     switch (type) {
  355.     case BOOLEAN:
  356.         return bool_from_termcap[idx];
  357.     case NUMBER:
  358.         return num_from_termcap[idx];
  359.     case STRING:
  360.         return str_from_termcap[idx];
  361.     }
  362.     break;
  363.     }
  364.  
  365.     return (FALSE);        /* pacify the compiler */
  366. }
  367.  
  368. static void
  369. force_wrap(void)
  370. {
  371.     oldcol = column;
  372.     strcpy_DYN(&outbuf, trailer);
  373.     column = INDENT;
  374. }
  375.  
  376. static void
  377. wrap_concat(const char *src)
  378. {
  379.     int need = strlen(src);
  380.     int want = strlen(separator) + need;
  381.  
  382.     if (column > INDENT
  383.     && column + want > width) {
  384.     force_wrap();
  385.     }
  386.     strcpy_DYN(&outbuf, src);
  387.     strcpy_DYN(&outbuf, separator);
  388.     column += need;
  389. }
  390.  
  391. #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
  392.     if ((size_t)(last - first) > sizeof(sep_trail)-1 \
  393.      && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
  394.          first += sizeof(sep_trail)-2
  395.  
  396. /* Returns the nominal length of the buffer assuming it is termcap format,
  397.  * i.e., the continuation sequence is treated as a single character ":".
  398.  *
  399.  * There are several implementations of termcap which read the text into a
  400.  * fixed-size buffer.  Generally they strip the newlines from the text, but may
  401.  * not do it until after the buffer is read.  Also, "tc=" resolution may be
  402.  * expanded in the same buffer.  This function is useful for measuring the size
  403.  * of the best fixed-buffer implementation; the worst case may be much worse.
  404.  */
  405. #ifdef TEST_TERMCAP_LENGTH
  406. static int
  407. termcap_length(const char *src)
  408. {
  409.     static const char pattern[] = ":\\\n\t:";
  410.  
  411.     int len = 0;
  412.     const char *const t = src + strlen(src);
  413.  
  414.     while (*src != '\0') {
  415.     IGNORE_SEP_TRAIL(src, t, pattern);
  416.     src++;
  417.     len++;
  418.     }
  419.     return len;
  420. }
  421. #else
  422. #define termcap_length(src) strlen(src)
  423. #endif
  424.  
  425. static char *
  426. fmt_complex(char *src, int level)
  427. {
  428.     int percent = 0;
  429.     int n;
  430.     bool if_then = strstr(src, "%?") != 0;
  431.     bool params = !if_then && (strlen(src) > 50) && (strstr(src, "%p") != 0);
  432.  
  433.     while (*src != '\0') {
  434.     switch (*src) {
  435.     case '\\':
  436.         percent = 0;
  437.         strncpy_DYN(&tmpbuf, src++, 1);
  438.         break;
  439.     case '%':
  440.         percent = 1;
  441.         break;
  442.     case '?':        /* "if" */
  443.     case 't':        /* "then" */
  444.     case 'e':        /* "else" */
  445.         if (percent) {
  446.         percent = 0;
  447.         tmpbuf.text[tmpbuf.used - 1] = '\n';
  448.         /* treat a "%e%?" as else-if, on the same level */
  449.         if (!strncmp(src, "e%?", 3)) {
  450.             for (n = 0; n < level; n++)
  451.             strncpy_DYN(&tmpbuf, "\t", 1);
  452.             strncpy_DYN(&tmpbuf, "%", 1);
  453.             strncpy_DYN(&tmpbuf, src, 3);
  454.             src += 3;
  455.         } else {
  456.             for (n = 0; n <= level; n++)
  457.             strncpy_DYN(&tmpbuf, "\t", 1);
  458.             strncpy_DYN(&tmpbuf, "%", 1);
  459.             strncpy_DYN(&tmpbuf, src, 1);
  460.             if (*src++ == '?') {
  461.             src = fmt_complex(src, level + 1);
  462.             } else if (level == 1) {
  463.             _nc_warning("%%%c without %%?", *src);
  464.             }
  465.         }
  466.         continue;
  467.         }
  468.         break;
  469.     case ';':        /* "endif" */
  470.         if (percent) {
  471.         percent = 0;
  472.         if (level > 1) {
  473.             tmpbuf.text[tmpbuf.used - 1] = '\n';
  474.             for (n = 0; n < level; n++)
  475.             strncpy_DYN(&tmpbuf, "\t", 1);
  476.             strncpy_DYN(&tmpbuf, "%", 1);
  477.             strncpy_DYN(&tmpbuf, src++, 1);
  478.             return src;
  479.         }
  480.         _nc_warning("%%; without %%?");
  481.         }
  482.         break;
  483.     case 'p':
  484.         if (percent && params) {
  485.         tmpbuf.text[tmpbuf.used - 1] = '\n';
  486.         for (n = 0; n <= level; n++)
  487.             strncpy_DYN(&tmpbuf, "\t", 1);
  488.         strncpy_DYN(&tmpbuf, "%", 1);
  489.         }
  490.         percent = 0;
  491.         break;
  492.     default:
  493.         percent = 0;
  494.         break;
  495.     }
  496.     strncpy_DYN(&tmpbuf, src++, 1);
  497.     }
  498.     return src;
  499. }
  500.  
  501. int
  502. fmt_entry(TERMTYPE * tterm,
  503.       int (*pred) (int type, int idx),
  504.       bool content_only,
  505.       bool suppress_untranslatable,
  506.       bool infodump,
  507.       int numbers)
  508. {
  509.     int i, j;
  510.     char buffer[MAX_TERMINFO_LENGTH];
  511.     NCURSES_CONST char *name;
  512.     int predval, len;
  513.     int num_bools = 0;
  514.     int num_values = 0;
  515.     int num_strings = 0;
  516.     bool outcount = 0;
  517.  
  518. #define WRAP_CONCAT    \
  519.     wrap_concat(buffer); \
  520.     outcount = TRUE
  521.  
  522.     len = 12;            /* terminfo file-header */
  523.  
  524.     if (pred == 0) {
  525.     cur_type = tterm;
  526.     pred = dump_predicate;
  527.     }
  528.  
  529.     strcpy_DYN(&outbuf, 0);
  530.     if (content_only) {
  531.     column = INDENT;    /* FIXME: workaround to prevent empty lines */
  532.     } else {
  533.     strcpy_DYN(&outbuf, tterm->term_names);
  534.     strcpy_DYN(&outbuf, separator);
  535.     column = outbuf.used;
  536.     force_wrap();
  537.     }
  538.  
  539.     for_each_boolean(j, tterm) {
  540.     i = BoolIndirect(j);
  541.     name = ExtBoolname(tterm, i, bool_names);
  542.  
  543.     if (!version_filter(BOOLEAN, i))
  544.         continue;
  545.     else if (isObsolete(outform, name))
  546.         continue;
  547.  
  548.     predval = pred(BOOLEAN, i);
  549.     if (predval != FAIL) {
  550.         (void) strcpy(buffer, name);
  551.         if (predval <= 0)
  552.         (void) strcat(buffer, "@");
  553.         else if (i + 1 > num_bools)
  554.         num_bools = i + 1;
  555.         WRAP_CONCAT;
  556.     }
  557.     }
  558.  
  559.     if (column != INDENT)
  560.     force_wrap();
  561.  
  562.     for_each_number(j, tterm) {
  563.     i = NumIndirect(j);
  564.     name = ExtNumname(tterm, i, num_names);
  565.  
  566.     if (!version_filter(NUMBER, i))
  567.         continue;
  568.     else if (isObsolete(outform, name))
  569.         continue;
  570.  
  571.     predval = pred(NUMBER, i);
  572.     if (predval != FAIL) {
  573.         if (tterm->Numbers[i] < 0) {
  574.         sprintf(buffer, "%s@", name);
  575.         } else {
  576.         sprintf(buffer, "%s#%d", name, tterm->Numbers[i]);
  577.         if (i + 1 > num_values)
  578.             num_values = i + 1;
  579.         }
  580.         WRAP_CONCAT;
  581.     }
  582.     }
  583.  
  584.     if (column != INDENT)
  585.     force_wrap();
  586.  
  587.     len += num_bools
  588.     + num_values * 2
  589.     + strlen(tterm->term_names) + 1;
  590.     if (len & 1)
  591.     len++;
  592.  
  593. #undef CUR
  594. #define CUR tterm->
  595.     if (outform == F_TERMCAP) {
  596.     if (termcap_reset != ABSENT_STRING) {
  597.         if (init_3string != ABSENT_STRING
  598.         && !strcmp(init_3string, termcap_reset))
  599.         DISCARD(init_3string);
  600.  
  601.         if (reset_2string != ABSENT_STRING
  602.         && !strcmp(reset_2string, termcap_reset))
  603.         DISCARD(reset_2string);
  604.     }
  605.     }
  606.  
  607.     for_each_string(j, tterm) {
  608.     i = StrIndirect(j);
  609.     name = ExtStrname(tterm, i, str_names);
  610.  
  611.     if (!version_filter(STRING, i))
  612.         continue;
  613.     else if (isObsolete(outform, name))
  614.         continue;
  615.  
  616.     /*
  617.      * Some older versions of vi want rmir/smir to be defined
  618.      * for ich/ich1 to work.  If they're not defined, force
  619.      * them to be output as defined and empty.
  620.      */
  621.     if (outform == F_TERMCAP) {
  622.         if (insert_character || parm_ich) {
  623.         if (&tterm->Strings[i] == &enter_insert_mode
  624.             && enter_insert_mode == ABSENT_STRING) {
  625.             (void) strcpy(buffer, "im=");
  626.             WRAP_CONCAT;
  627.             continue;
  628.         }
  629.  
  630.         if (&tterm->Strings[i] == &exit_insert_mode
  631.             && exit_insert_mode == ABSENT_STRING) {
  632.             (void) strcpy(buffer, "ei=");
  633.             WRAP_CONCAT;
  634.             continue;
  635.         }
  636.         }
  637.     }
  638.  
  639.     predval = pred(STRING, i);
  640.     buffer[0] = '\0';
  641.  
  642.     if (predval != FAIL) {
  643.         if (tterm->Strings[i] != ABSENT_STRING
  644.         && i + 1 > num_strings)
  645.         num_strings = i + 1;
  646.  
  647.         if (!VALID_STRING(tterm->Strings[i])) {
  648.         sprintf(buffer, "%s@", name);
  649.         WRAP_CONCAT;
  650.         } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
  651.         int params = ((i < (int) SIZEOF(parametrized))
  652.                   ? parametrized[i]
  653.                   : 0);
  654.         char *srccap = _nc_tic_expand(tterm->Strings[i], TRUE, numbers);
  655.         char *cv = _nc_infotocap(name, srccap, params);
  656.  
  657.         if (cv == 0) {
  658.             if (outform == F_TCONVERR) {
  659.             sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!",
  660.                 name, srccap);
  661.             } else if (suppress_untranslatable) {
  662.             continue;
  663.             } else {
  664.             char *s = srccap, *d = buffer;
  665.             sprintf(d, "..%s=", name);
  666.             d += strlen(d);
  667.             while ((*d = *s++) != 0) {
  668.                 if (*d == ':') {
  669.                 *d++ = '\\';
  670.                 *d = ':';
  671.                 } else if (*d == '\\') {
  672.                 *++d = *s++;
  673.                 }
  674.                 d++;
  675.             }
  676.             }
  677.         } else {
  678.             sprintf(buffer, "%s=%s", name, cv);
  679.         }
  680.         len += strlen(tterm->Strings[i]) + 1;
  681.         WRAP_CONCAT;
  682.         } else {
  683.         char *src = _nc_tic_expand(tterm->Strings[i],
  684.                        outform == F_TERMINFO, numbers);
  685.  
  686.         strcpy_DYN(&tmpbuf, 0);
  687.         strcpy_DYN(&tmpbuf, name);
  688.         strcpy_DYN(&tmpbuf, "=");
  689.         if (pretty
  690.             && (outform == F_TERMINFO
  691.             || outform == F_VARIABLE)) {
  692.             fmt_complex(src, 1);
  693.         } else {
  694.             strcpy_DYN(&tmpbuf, src);
  695.         }
  696.         len += strlen(tterm->Strings[i]) + 1;
  697.         wrap_concat(tmpbuf.text);
  698.         outcount = TRUE;
  699.         }
  700.     }
  701.     }
  702.     len += num_strings * 2;
  703.  
  704.     /*
  705.      * This piece of code should be an effective inverse of the functions
  706.      * postprocess_terminfo and postprocess_terminfo in parse_entry.c.
  707.      * Much more work should be done on this to support dumping termcaps.
  708.      */
  709.     if (tversion == V_HPUX) {
  710.     if (memory_lock) {
  711.         (void) sprintf(buffer, "meml=%s", memory_lock);
  712.         WRAP_CONCAT;
  713.     }
  714.     if (memory_unlock) {
  715.         (void) sprintf(buffer, "memu=%s", memory_unlock);
  716.         WRAP_CONCAT;
  717.     }
  718.     } else if (tversion == V_AIX) {
  719.     if (VALID_STRING(acs_chars)) {
  720.         bool box_ok = TRUE;
  721.         const char *acstrans = "lqkxjmwuvtn";
  722.         const char *cp;
  723.         char *tp, *sp, boxchars[11];
  724.  
  725.         tp = boxchars;
  726.         for (cp = acstrans; *cp; cp++) {
  727.         sp = strchr(acs_chars, *cp);
  728.         if (sp)
  729.             *tp++ = sp[1];
  730.         else {
  731.             box_ok = FALSE;
  732.             break;
  733.         }
  734.         }
  735.         tp[0] = '\0';
  736.  
  737.         if (box_ok) {
  738.         (void) strcpy(buffer, "box1=");
  739.         (void) strcat(buffer, _nc_tic_expand(boxchars,
  740.                              outform == F_TERMINFO, numbers));
  741.         WRAP_CONCAT;
  742.         }
  743.     }
  744.     }
  745.  
  746.     /*
  747.      * kludge: trim off trailer to avoid an extra blank line
  748.      * in infocmp -u output when there are no string differences
  749.      */
  750.     if (outcount) {
  751.     bool trimmed = FALSE;
  752.     j = outbuf.used;
  753.     if (j >= 2
  754.         && outbuf.text[j - 1] == '\t'
  755.         && outbuf.text[j - 2] == '\n') {
  756.         outbuf.used -= 2;
  757.         trimmed = TRUE;
  758.     } else if (j >= 4
  759.            && outbuf.text[j - 1] == ':'
  760.            && outbuf.text[j - 2] == '\t'
  761.            && outbuf.text[j - 3] == '\n'
  762.            && outbuf.text[j - 4] == '\\') {
  763.         outbuf.used -= 4;
  764.         trimmed = TRUE;
  765.     }
  766.     if (trimmed) {
  767.         outbuf.text[outbuf.used] = '\0';
  768.         column = oldcol;
  769.     }
  770.     }
  771. #if 0
  772.     fprintf(stderr, "num_bools = %d\n", num_bools);
  773.     fprintf(stderr, "num_values = %d\n", num_values);
  774.     fprintf(stderr, "num_strings = %d\n", num_strings);
  775.     fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
  776.         tterm->term_names, len, outbuf.used, outbuf.text);
  777. #endif
  778.     /*
  779.      * Here's where we use infodump to trigger a more stringent length check
  780.      * for termcap-translation purposes.
  781.      * Return the length of the raw entry, without tc= expansions,
  782.      * It gives an idea of which entries are deadly to even *scan past*,
  783.      * as opposed to *use*.
  784.      */
  785.     return (infodump ? len : (int) termcap_length(outbuf.text));
  786. }
  787.  
  788. static bool
  789. kill_string(TERMTYPE * tterm, char *cap)
  790. {
  791.     int n;
  792.     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
  793.     if (cap == tterm->Strings[n]) {
  794.         tterm->Strings[n] = ABSENT_STRING;
  795.         return TRUE;
  796.     }
  797.     }
  798.     return FALSE;
  799. }
  800.  
  801. static char *
  802. find_string(TERMTYPE * tterm, char *name)
  803. {
  804.     int n;
  805.     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
  806.     if (version_filter(STRING, n)
  807.         && !strcmp(name, strnames[n])) {
  808.         char *cap = tterm->Strings[n];
  809.         if (VALID_STRING(cap)) {
  810.         return cap;
  811.         }
  812.         break;
  813.     }
  814.     }
  815.     return ABSENT_STRING;
  816. }
  817.  
  818. /*
  819.  * This is used to remove function-key labels from a termcap entry to
  820.  * make it smaller.
  821.  */
  822. static int
  823. kill_labels(TERMTYPE * tterm, int target)
  824. {
  825.     int n;
  826.     int result = 0;
  827.     char *cap;
  828.     char name[10];
  829.  
  830.     for (n = 0; n <= 10; ++n) {
  831.     sprintf(name, "lf%d", n);
  832.     if ((cap = find_string(tterm, name)) != ABSENT_STRING
  833.         && kill_string(tterm, cap)) {
  834.         target -= (strlen(cap) + 5);
  835.         ++result;
  836.         if (target < 0)
  837.         break;
  838.     }
  839.     }
  840.     return result;
  841. }
  842.  
  843. /*
  844.  * This is used to remove function-key definitions from a termcap entry to
  845.  * make it smaller.
  846.  */
  847. static int
  848. kill_fkeys(TERMTYPE * tterm, int target)
  849. {
  850.     int n;
  851.     int result = 0;
  852.     char *cap;
  853.     char name[10];
  854.  
  855.     for (n = 60; n >= 0; --n) {
  856.     sprintf(name, "kf%d", n);
  857.     if ((cap = find_string(tterm, name)) != ABSENT_STRING
  858.         && kill_string(tterm, cap)) {
  859.         target -= (strlen(cap) + 5);
  860.         ++result;
  861.         if (target < 0)
  862.         break;
  863.     }
  864.     }
  865.     return result;
  866. }
  867.  
  868. #define FMT_ENTRY() \
  869.         fmt_entry(tterm, pred, \
  870.             (already_used > 0), \
  871.             suppress_untranslatable, \
  872.             infodump, numbers)
  873.  
  874. #define SHOW_WHY if (!already_used) PRINTF
  875.  
  876. int
  877. dump_entry(TERMTYPE * tterm,
  878.        bool suppress_untranslatable,
  879.        bool limited,
  880.        int already_used,
  881.        int numbers,
  882.        int (*pred) (int type, int idx))
  883. /* dump a single entry */
  884. {
  885.     int len, critlen;
  886.     const char *legend;
  887.     bool infodump;
  888.  
  889.     if (outform == F_TERMCAP || outform == F_TCONVERR) {
  890.     critlen = MAX_TERMCAP_LENGTH;
  891.     legend = "older termcap";
  892.     infodump = FALSE;
  893.     set_obsolete_termcaps(tterm);
  894.     } else {
  895.     critlen = MAX_TERMINFO_LENGTH;
  896.     legend = "terminfo";
  897.     infodump = TRUE;
  898.     }
  899.     critlen -= already_used;
  900.  
  901.     if (((len = FMT_ENTRY()) > critlen)
  902.     && limited) {
  903.     if (!suppress_untranslatable) {
  904.         SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
  905.              critlen);
  906.         suppress_untranslatable = TRUE;
  907.     }
  908.     if ((len = FMT_ENTRY()) > critlen) {
  909.         /*
  910.          * We pick on sgr because it's a nice long string capability that
  911.          * is really just an optimization hack.  Another good candidate is
  912.          * acsc since it is both long and unused by BSD termcap.
  913.          */
  914.         char *oldsgr = set_attributes;
  915.         char *oldacsc = acs_chars;
  916.         set_attributes = ABSENT_STRING;
  917.         SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
  918.              critlen);
  919.         if ((len = FMT_ENTRY()) > critlen) {
  920.         acs_chars = ABSENT_STRING;
  921.         SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
  922.              critlen);
  923.         }
  924.         if ((len = FMT_ENTRY()) > critlen) {
  925.         int oldversion = tversion;
  926.  
  927.         tversion = V_BSD;
  928.         SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
  929.              critlen);
  930.  
  931.         len = FMT_ENTRY();
  932.         if (len > critlen
  933.             && kill_labels(tterm, len - critlen)) {
  934.             SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
  935.                  critlen);
  936.             len = FMT_ENTRY();
  937.         }
  938.         if (len > critlen
  939.             && kill_fkeys(tterm, len - critlen)) {
  940.             SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
  941.                  critlen);
  942.             len = FMT_ENTRY();
  943.         }
  944.         if (len > critlen && !already_used) {
  945.             (void) fprintf(stderr,
  946.                    "warning: %s entry is %d bytes long\n",
  947.                    _nc_first_name(tterm->term_names),
  948.                    len);
  949.             SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
  950.                  already_used + len, legend);
  951.         }
  952.         tversion = oldversion;
  953.         }
  954.         set_attributes = oldsgr;
  955.         acs_chars = oldacsc;
  956.     }
  957.     }
  958.  
  959.     (void) fputs(outbuf.text, stdout);
  960.     return len;
  961. }
  962.  
  963. int
  964. dump_uses(const char *name, bool infodump)
  965. /* dump "use=" clauses in the appropriate format */
  966. {
  967.     char buffer[MAX_TERMINFO_LENGTH];
  968.  
  969.     strcpy_DYN(&outbuf, 0);
  970.     (void) sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
  971.     wrap_concat(buffer);
  972.     (void) fputs(outbuf.text, stdout);
  973.     return outbuf.used;
  974. }
  975.  
  976. void
  977. compare_entry(void (*hook) (int t, int i, const char *name), TERMTYPE * tp
  978.           GCC_UNUSED, bool quiet)
  979. /* compare two entries */
  980. {
  981.     int i, j;
  982.     NCURSES_CONST char *name;
  983.  
  984.     if (!quiet)
  985.     fputs("    comparing booleans.\n", stdout);
  986.     for_each_boolean(j, tp) {
  987.     i = BoolIndirect(j);
  988.     name = ExtBoolname(tp, i, bool_names);
  989.  
  990.     if (isObsolete(outform, name))
  991.         continue;
  992.  
  993.     (*hook) (CMP_BOOLEAN, i, name);
  994.     }
  995.  
  996.     if (!quiet)
  997.     fputs("    comparing numbers.\n", stdout);
  998.     for_each_number(j, tp) {
  999.     i = NumIndirect(j);
  1000.     name = ExtNumname(tp, i, num_names);
  1001.  
  1002.     if (isObsolete(outform, name))
  1003.         continue;
  1004.  
  1005.     (*hook) (CMP_NUMBER, i, name);
  1006.     }
  1007.  
  1008.     if (!quiet)
  1009.     fputs("    comparing strings.\n", stdout);
  1010.     for_each_string(j, tp) {
  1011.     i = StrIndirect(j);
  1012.     name = ExtStrname(tp, i, str_names);
  1013.  
  1014.     if (isObsolete(outform, name))
  1015.         continue;
  1016.  
  1017.     (*hook) (CMP_STRING, i, name);
  1018.     }
  1019.  
  1020.     /* (void) fputs("    comparing use entries.\n", stdout); */
  1021.     (*hook) (CMP_USE, 0, "use");
  1022.  
  1023. }
  1024.  
  1025. #define NOTSET(s)    ((s) == 0)
  1026.  
  1027. /*
  1028.  * This bit of legerdemain turns all the terminfo variable names into
  1029.  * references to locations in the arrays Booleans, Numbers, and Strings ---
  1030.  * precisely what's needed.
  1031.  */
  1032. #undef CUR
  1033. #define CUR tp->
  1034.  
  1035. static void
  1036. set_obsolete_termcaps(TERMTYPE * tp)
  1037. {
  1038. #include "capdefaults.c"
  1039. }
  1040.  
  1041. /*
  1042.  * Convert an alternate-character-set string to canonical form: sorted and
  1043.  * unique.
  1044.  */
  1045. void
  1046. repair_acsc(TERMTYPE * tp)
  1047. {
  1048.     if (VALID_STRING(acs_chars)) {
  1049.     size_t n, m;
  1050.     char mapped[256];
  1051.     char extra = 0;
  1052.     unsigned source;
  1053.     unsigned target;
  1054.     bool fix_needed = FALSE;
  1055.  
  1056.     for (n = 0, source = 0; acs_chars[n] != 0; n++) {
  1057.         target = acs_chars[n];
  1058.         if (source >= target) {
  1059.         fix_needed = TRUE;
  1060.         break;
  1061.         }
  1062.         source = target;
  1063.         if (acs_chars[n + 1])
  1064.         n++;
  1065.     }
  1066.     if (fix_needed) {
  1067.         memset(mapped, 0, sizeof(mapped));
  1068.         for (n = 0; acs_chars[n] != 0; n++) {
  1069.         source = acs_chars[n];
  1070.         if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
  1071.             mapped[source] = target;
  1072.             n++;
  1073.         } else {
  1074.             extra = source;
  1075.         }
  1076.         }
  1077.         for (n = m = 0; n < sizeof(mapped); n++) {
  1078.         if (mapped[n]) {
  1079.             acs_chars[m++] = n;
  1080.             acs_chars[m++] = mapped[n];
  1081.         }
  1082.         }
  1083.         if (extra)
  1084.         acs_chars[m++] = extra;        /* garbage in, garbage out */
  1085.         acs_chars[m] = 0;
  1086.     }
  1087.     }
  1088. }
  1089.